#!/usr/bin/env node
import { fork } from 'child_process'
import { resolve } from 'path'
import { Argv, IPlugin } from 'ssr-types'
import * as yargs from 'yargs'
import { generateHtml } from './html'
import { handleEnv } from './preprocess'
import { ssg } from './ssg'
import { createWatcher, onWatcher } from './watcher'
import { addChunkNameInRoutes } from './add-chunk-name'

const spinnerProcess = fork(resolve(__dirname, './spinner')) // 单独创建子进程跑 spinner 否则会被后续的 同步代码 block 导致 loading 暂停

const spinner = {
	start: () =>
		spinnerProcess.send({
			message: 'start'
		}),
	stop: () =>
		spinnerProcess.send({
			message: 'stop'
		})
}

const startOrBuild = async (argv: Argv, type: 'start' | 'build') => {
	const { judgeFramework, judgeServerFramework, logGreen, getCwd } = await import('ssr-common-utils')
	const cwd = getCwd()
	const framework = judgeFramework()
	const serverFramework = judgeServerFramework()
	if (argv.ssg) {
		logGreen('Using ssg for generate static html file')
	}
	if (!argv.api) {
		const { clientPlugin } = await import(resolve(cwd, './node_modules', framework))
		const client: IPlugin['clientPlugin'] = clientPlugin()
		await client?.[type]?.(argv)
	}
	if (!argv.web) {
		const { serverPlugin } = await import(resolve(cwd, './node_modules', serverFramework))
		const server: IPlugin['serverPlugin'] = serverPlugin()
		await server?.[type]?.(argv)
	}
	if (type === 'build') {
		await generateHtml()
		await ssg(argv)
	}
}

const startFunc = async (argv: Argv) => {
	await handleEnv(argv)
	if (argv.tool !== 'vite') {
		spinner.start()
	}
	process.env.NODE_ENV = 'development'
	const { parseFeRoutes, transformConfig, logInfo } = await import('ssr-common-utils')
	await transformConfig()
	if (argv.tool === 'vite') {
		logInfo('Vite 场景本地开发样式闪烁为正常现象请忽略，生产环境无此问题')
	}
	const watcher = await createWatcher()
	await parseFeRoutes()
	await addChunkNameInRoutes()
	spinner.stop()
	await startOrBuild(argv, 'start')
	await onWatcher(watcher)
}

const buildFunc = async (argv: Argv) => {
	await handleEnv(argv)
	spinner.start()
	process.env.NODE_ENV = 'production'
	const { parseFeRoutes, transformConfig } = await import('ssr-common-utils')
	await transformConfig()
	await parseFeRoutes()
	await addChunkNameInRoutes()
	spinner.stop()
	await startOrBuild(argv, 'build')
}

const deployFunc = async (argv: Argv) => {
	process.env.NODE_ENV = 'production'
	const { judgeServerFramework } = await import('ssr-common-utils')
	const serverFramework = judgeServerFramework()
	const { serverPlugin } = await import(serverFramework)
	const server: IPlugin['serverPlugin'] = serverPlugin()
	if (!server?.deploy) {
		console.log(
			'当前插件不支持 deploy 功能，请使用 ssr-plugin-midway 插件 参考 https://www.yuque.com/midwayjs/faas/migrate_egg 或扫码进群了解'
		)
		return
	}
	await server?.deploy?.(argv)
	spinner.stop()
}

const cliDesc = {
	web: {
		desc: 'only start client plugin'
	},
	api: {
		desc: 'only start server plugin'
	}
}
yargs
	.command(
		'start',
		'Start Server',
		(yargs) =>
			yargs.options({
				bundleConfig: {
					alias: 'bc',
					desc: 'bundle config.ts dependencies module by esbuild'
				},
				analyze: {
					alias: 'a',
					desc: 'Analyze bundle result when using webpack for build'
				},
				tool: {
					desc: 'Start application by vite or rspack',
					choices: ['webpack', 'vite', 'rspack'],
					default: 'webpack'
				},
				viteMode: {
					desc: 'same like vite start --mode'
				},
				port: {
					desc: 'Setting application server port, default is 3000'
				},
				help: {
					alias: 'h',
					desc: 'In midway, use --help to speed up ts compile'
				},
				nominify: {
					desc: 'Disable minify output file content for debug'
				},
				sourcemap: {
					desc: 'Set type of generate sourcemap by ssr start --sourcemap xxx'
				},
				'client-sourcemap': {
					desc: 'Set type of generate sourcemap for client-side code'
				},
				'server-sourcemap': {
					desc: 'Set type of generate sourcemap for server-side code'
				},
				...cliDesc
			}),
		async (argv: Argv) => {
			if (argv.bc) {
				process.env.BUNDLECONFIG = '1'
			}
			await startFunc(argv)
		}
	)
	.command(
		'build',
		'Build application by webpack or vite',
		(yargs) =>
			yargs.options({
				bundleConfig: {
					alias: 'bc',
					desc: 'bundle config.ts dependencies module by esbuild'
				},
				analyze: {
					alias: 'a',
					desc: 'Analyze bundle result when using webpack for build'
				},
				vite: {
					desc: 'Build application by vite'
				},
				viteMode: {
					desc: 'same like vite build --mode'
				},
				html: {
					desc: 'Build application as a single html'
				},
				ssg: {
					desc: 'Build with Static Site Generation (Pre Render)'
				},
				sourcemap: {
					desc: 'Set type of generate sourcemap by build --sourcemap xxx'
				},
				'client-sourcemap': {
					desc: 'Set type of generate sourcemap for client-side code'
				},
				'server-sourcemap': {
					desc: 'Set type of generate sourcemap for server-side code'
				},
				nominify: {
					desc: 'Disable minify output file content for debug'
				},
				...cliDesc
			}),
		async (argv: Argv) => {
			if (argv.bc) {
				process.env.BUNDLECONFIG = '1'
			}
			await buildFunc(argv)
		}
	)
	.command(
		'deploy',
		'Deploy function to aliyun cloud or tencent cloud',
		(yargs) =>
			yargs.options({
				tencent: {
					desc: 'deploy application to tencent clound'
				}
			}),
		async (argv: Argv) => {
			await deployFunc(argv)
		}
	)
	.command('update', 'check dependencies version is latest', {}, async (_argv: Argv) => {
		spinner.start()
		const { update } = await import('./update')
		await update()
		spinner.stop()
	})
	.demandCommand(1, 'You need at least one command before moving on')
	.option('version', {
		alias: 'v',
		default: false,
		desc: 'Show current version'
	})
	.fail((msg, err) => {
		if (err) {
			console.log(err)
			spinner.stop()
			process.exit(1)
		}
		console.log(msg)
	})
	.parse()

export { startFunc, buildFunc, deployFunc }
